#include <stdlib.h>
#include <iostream>
#include <windows.h>
#include <stdarg.h>
#include <math.h>

using namespace std;

typedef union
{
	int _int;
	long long _long;
	char _char;
	float _float;
	void *_pointer; 
} Variant;

extern "C"
{
	int callAssemblerFunctionInt(void *func, void *args, int argsSize, int convention);

	int sumaInfinita(int numberOfParams, ...)
	{
		va_list lst;
		va_start(lst, numberOfParams);
		int res = 0;
		int val = 0;
		
        for (; numberOfParams > 0; numberOfParams--) 
                res += va_arg(lst, int); 
	
		va_end(lst);
		return res;
	}

	bool executeFunctionFromLibrary(const char *libFileName, const char *functionName, Variant *returnValue, void *args, int argsSize)
	{
		HMODULE lib = LoadLibraryA(libFileName);
		if (!lib) return false;

		void *func = GetProcAddress(lib, functionName);
		if (!func) return false;

		double floatResult = 0;

		returnValue->_int = callAssemblerFunctionInt(func, args, argsSize, 2);

		/*if (returnFloat)
			returnValue->_float = (float) floatResult;*/

		FreeLibrary(lib);
		return true;
	}

	void *allocMem(int size)
	{
		char *ptr = new char[size];

		for (int i = 0; i < size; i++)
			ptr[i] = 0;

		return ptr;
	}

	void freeMem(void *ptr)
	{
		delete[] (char *) ptr;
	}

	void *putInt(int *ptr, int value)
	{
		*ptr = value;
		return ((char *) ptr) + 4;
	}

	void *putChar(char *ptr, char value)
	{
		*ptr = value;
		return ptr + 4;
	}

	void *putFloat(float *ptr, float value)
	{
		*ptr = value;
		return ((char *) ptr) + 4;
	}

	void *putPointer(void **ptr, void *value)
	{
		*ptr = value;
		return ((char *) ptr) + 4;
	}

	float sumarCharIntFloat(char c, int i, float f)
	{
		return f + (float) i + (float) c;
	}
}

//void generalTest1()
//{
//	Variant result;
//
//	result._float = 0;
//
//	void *args = allocMem(12);
//	void *temp = args;
//
//	temp = putFloat((float *) temp, 1.2f);
//	temp = putInt((int *) temp, 5);
//	temp = putChar((char *) temp, 3);
//
//	cout << executeFunctionFromLibrary("DllForTest.dll", "sumarCharIntFloat", &result, args, 12, true) << endl;
//	cout << "resultado:" << result._float << endl;
//	cout << "real: " << sumarCharIntFloat(3, 5, 1.2f) << endl;
//
//	freeMem(args);
//}

//void generalTest2()
//{
//	Variant result;
//
//	result._int = 0;
//
//	void *args = allocMem(24);
//	void *temp = args;
//
//	temp = putInt((int *) temp, 2);
//	temp = putInt((int *) temp, 14);
//	temp = putChar((char *) temp, ' ');
//	temp = putChar((char *) temp, ' ');
//	temp = putChar((char *) temp, ' ');
//	temp = putChar((char *) temp, ' ');
//
//	cout << executeFunctionFromLibrary("DllForTest.dll", "sumarTodo", &result, args, 24, false) << endl;
//	cout << result._int << endl;
//
//	freeMem(args);
//}

void laPutaMadre()
{
	void *args = allocMem(20);
	void *temp = args;

	temp = putInt((int *) temp, 1);
	temp = putInt((int *) temp, 2);
	temp = putInt((int *) temp, 3);
	temp = putInt((int *) temp, 4);
	temp = putInt((int *) temp, 2);

	Variant res;

	executeFunctionFromLibrary("DllForTest.dll", "sumaYDivideRegister", &res, args, 20);
	//callAssemblerFunctionVoid(NULL, args, 8, 0);
}

int main()
{
	//generalTest1();
	//generalTest2();

	cout << "hola" << endl;

	laPutaMadre();

	system("pause");
	return 0;
}
